#pragma once

#include "util.hpp"
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <functional>
#include "buffer.hpp"

class AsyncLooper
{
public:
    using Functor = std::function<void(Buffer &buffer)>;
    using ptr = std::shared_ptr<AsyncLooper>;
    AsyncLooper(const Functor &cb)
        : _running(true), _looper_callback(cb), _thread(&AsyncLooper::worker_loop, this)
    {
    }

    ~AsyncLooper()
    {
        stop();
    }

    void stop()
    {
        _running = false;
        _pop_cond.notify_all();
        _thread.join();
    }

    void push(const std::string &msg)
    {
        if (_running == false)
        {
            return;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        _push_cond.wait(lock, [&]
                        { return _tasks_push.writeAbleSize() >= msg.size(); });
        _tasks_push.push(msg.c_str(), msg.size());

        _pop_cond.notify_all();
    }

private:
    void worker_loop()//后台线程
    {
        while (1)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            //线程不在运行或者主线程没有收到数据
            if (_running == false && _tasks_push.empty())
            {
                return;
            }
            _pop_cond.wait(lock, [&]
                           { return !_tasks_push.empty() || !_running; });
            _tasks_push.swap(_tasks_pop);

            _push_cond.notify_all();
            _looper_callback(_tasks_pop);
            _tasks_pop.reset();
        }

        return;
    }

private:
    Functor _looper_callback;//回调函数，接收到数据后要怎样处理

    std::mutex _mutex;//线程锁，只允许一个人访问共享资源
    std::atomic<bool> _running;
    std::condition_variable _push_cond;//等待传入的数据队列
    std::condition_variable _pop_cond;//等待处理的数据队列
    Buffer _tasks_push;//主线程收到的数据
    Buffer _tasks_pop;//其他线程正在处理的数据
    std::thread _thread;
};
